#pragma once
#include "../UIElement.h"
#include "../IUITextElement.h"

class UIButton : public UIElement, public IUITextElement
{
public:
	UIButton();
	UIButton(float x, float y);
	UIButton(float x, float y, float width, float height);
	UIButton(float x, float y, float width, float height, std::string Text);
	UIButton(float x, float y, float width, float height, std::string Text, std::string FontName);
	UIButton(float x, float y, float width, float height, std::string Text, std::string FontName, int FontSize);
	UIButton(float x, float y, float width, float height, std::string Text, std::string FontName, int FontSize, Color color);
	UIButton(float x, float y, float width, float height, std::string Text, std::string FontName, int FontSize, Color color, bool roundedCornersEnabled);
	UIButton(float x, float y, float width, float height, std::string Text, std::string FontName, int FontSize, Color color, bool roundedCornersEnabled, float roundedCornerRadiusX, float roundedCornerRadiusY);

	// Draws the element on the screen and has to be called between graphics.BeginDraw() and graphics.EndDraw()
	void __stdcall Draw(Graphics* graphics);

	Color HoverOnColor = Color::DarkGray;
	Color BorderColor = Color(40, 40, 40, 255);
	float BorderStroke = 2.0f;
	float Stroke = 1.0f;
	float Margins = 0.1f;
	bool Filled = true;
	bool RoundedCorners = true;
	float RoundCornerRadiusX = 4, RoundCornerRadiusY = 4;

	// This function is only used in private callback events, please don't use this
	void SetHoverOffColor(Color color) { this->hoverOffColor = color; }

	// This function is only used in private callback events, please don't use this
	Color GetHoverOffColor() { return this->hoverOffColor; }

	// Set enabled state of the element
	void SetEnabled(bool state)
	{
		enabled = state;
		if (state)
		{
			color.a = normalAlpha;
			BorderColor.a = normalAlpha;
			TextColor.a = normalAlpha;
		}
		else
		{
			color.a = 36;
			BorderColor.a = 36;
			TextColor.a = 36;
		}
	}

	// Fades the element out over given period of time in miliseconds
	void __stdcall FadeOut(int time)
	{
		std::thread fadeout_thread([this, &time]
		{
			Color currentColor = color;
			float currentAlpha = currentColor.a;
			if (currentAlpha == 0) { currentAlpha = 1; }
			int sleepIntervals = time / (int)currentAlpha;
			for (float i = currentAlpha; i > 0; i--)
			{
				currentColor.a--;
				this->color = currentColor;

				Color newTextColor = TextColor;
				newTextColor.a = currentColor.a;
				this->TextColor = newTextColor;

				Color newBorderColor = BorderColor;
				newBorderColor.a = currentColor.a;
				this->BorderColor = newBorderColor;

				Sleep(sleepIntervals);
			}
			this->Visible = false;
		});
		fadeout_thread.join();
	}

	// Fades the element in over given period of time in miliseconds until the needed alpha value is reached
	void __stdcall FadeIn(int time, int finalAlpha = 255)
	{
		int sleepInterval = 0;
		if (finalAlpha < color.a) return; // invalid alpha state
		int delta = finalAlpha - color.a;
		if (delta == 0)
		{
			sleepInterval = time;
		}
		else
		{
			sleepInterval = time / delta;
		}

		if (finalAlpha >= 255)
			finalAlpha = 254;

		std::thread fadein_thread([this, sleepInterval, finalAlpha] {
			this->Visible = true;
			for (int i = color.a; i <= finalAlpha; i++)
			{
				Sleep(sleepInterval);
				uint8_t val = (uint8_t)i;
				color.a = val;


				Color newTextColor = TextColor;
				newTextColor.a = color.a;
				this->TextColor = newTextColor;

				this->normalAlpha = color.a;
			}
			EmergencySetHoverOffColor();
		});
		fadein_thread.detach();
	}

private:
	// during fadeout animation if a button is clicked hover off listener wouldn't react during animation, so we need to do it manually
	void EmergencySetHoverOffColor();
	void SetDefaultOptions();
	void SetInternalHoverEventListeners();
	Color hoverOffColor = color;
};

